/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../macro/head.h"
#include "ssl_impl.h"
#include "ssl_mgr.h"
#include "mgr.h"

namespace xos_encrypt
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static ssl_mgr::ITEM_DATA xos_item_data;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    ssl_mgr::ssl_mgr()
    {
        init_data();
    }

    ssl_mgr::~ssl_mgr()
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int ssl_mgr::sni_callback( SSL * ssl, int * ad, void * arg ) 
    {
        const char * servername = SSL_get_servername( ssl, TLSEXT_NAMETYPE_host_name );
        if( servername ) 
        {
            SSL_CTX * ctx = 0;
            {
                xos_box::i_str_property * pProp = mgr::ssl_ctx_prop();
                ssl_mgr * pMgr = 0;
                if( pProp )
                {
                    pMgr = (ssl_mgr *)pProp->obj( servername );
                }
                if( pMgr )
                {
                    ctx = pMgr->m_pCtx;
                }
            }
            if( ctx ) 
            {
                SSL_set_SSL_CTX( ssl, ctx );
            }
        }
        return SSL_TLSEXT_ERR_OK;
    }

    int ssl_mgr::get_xos_item_data( ITEM_DATA *& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int ssl_mgr::set_server_domain( const char * lpszDomain )
    {
        int ret = 0;
        m_server_domain = lpszDomain;
        return ret;
    }

    int ssl_mgr::set_cert( const char * lpszFile )
    {
        int ret = 0;
        m_cert = lpszFile;
        return ret;
    }

    int ssl_mgr::set_key( const char * lpszFile )
    {
        int ret = 0;
        m_key = lpszFile;
        return ret;
    }

    int ssl_mgr::init_ssl( bool bServer )
    {
        int ret = 0;

        SSL_CTX * pCtx = 0;

        if( 0 == ret )
        {
            m_bServer = bServer;
            if( bServer )
            {
                //pCtx = SSL_CTX_new( SSLv23_server_method() );
                pCtx = SSL_CTX_new( TLS_server_method() );
            }
            else
            {
                //pCtx = SSL_CTX_new( SSLv23_client_method() );
                pCtx = SSL_CTX_new( TLS_client_method() );
            }
            if( !pCtx )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_cert.empty() )
        {
            int r = SSL_CTX_use_certificate_file( pCtx, m_cert.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_key.empty() )
        {
            int r = SSL_CTX_use_PrivateKey_file( pCtx, m_key.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_key.empty() )
        {
            int r = SSL_CTX_check_private_key( pCtx );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && bServer )
        {
            SSL_CTX_set_tlsext_servername_callback( pCtx, sni_callback );
        }

        if( 0 == ret )
        {
            m_pCtx = pCtx;
        }
        else
        {
            SSL_CTX_free( pCtx );
        }

        return ret;
    }

    i_ssl * ssl_mgr::ssl()
    {
        ssl_impl::T * pT = 0;
        xos_stl::init_pool_item( pT );
        pT->set_mgr( this );
        return pT;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int ssl_mgr::init_data()
    {
        int ret = 0;

        m_bServer = true;
        m_server_domain = "";
        m_cert = "";
        m_key = "";
        m_pCtx = 0;

        return ret;
    }

    int ssl_mgr::term_ssl()
    {
        int ret = 0;

        if( m_pCtx )
        {
            SSL_CTX_free( m_pCtx );
            m_pCtx = 0;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int ssl_mgr::init()
    {
        int ret = 0;
        return ret;
    }

    int ssl_mgr::term()
    {
        int ret = 0;
        term_ssl();
        init_data();
        return ret;
    }


} // xos_encrypt
